package cn.qdhlm.collectservice.core.component.command;


import cn.qdhlm.collectservice.common.Constant;
import cn.qdhlm.collectservice.common.helper.RedisHelper;
import cn.qdhlm.collectservice.common.util.CodeUtil;
import cn.qdhlm.collectservice.common.util.ComUtil;
import cn.qdhlm.collectservice.common.util.JsonUtil;
import cn.qdhlm.collectservice.model.dto.CommandParamDTO;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.log4j.Log4j2;

import java.math.BigDecimal;

/**
 * @Name: AnyAfn0c
 * @Description: 控制
 * @Author: jiangcs
 */
@Log4j2
public class CmdAfn0c {
    /**
     * f1 透传报文: 读阀门数据
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf f1(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBuf901f = pack901f(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBuf901f.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBuf901f);
    }

    /**
     * f2: 主动发送完毕后 进入休眠
     *
     * @param sn
     * @return
     */
    public static ByteBuf f2(int sn) {
        ByteBuf byteBuf = Unpooled.buffer(2);
        // 数据单元标识：FN
        byteBuf.writeByte(0x02);
        // 数据包序号
        byteBuf.writeByte(sn);
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * f3：强制设温
     *
     * @param sn
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf f3(int sn, CommandParamDTO commandParamDTO) {
        Double temperatureSet = commandParamDTO.getTemperatureSet();
        if (ComUtil.isEmpty(temperatureSet)) {
            log.error("f3: temperatureSet is empty");
            return null;
        }
        Double temperatureUpper = commandParamDTO.getTemperatureUpper();
        if (ComUtil.isEmpty(temperatureUpper)) {
            log.error("f3: temperatureUpper is empty");
            return null;
        }
        Double temperatureLower = commandParamDTO.getTemperatureLower();
        if (ComUtil.isEmpty(temperatureLower)) {
            log.error("f3: temperatureLower is empty");
            return null;
        }
        Double adjustDeadZone = commandParamDTO.getAdjustDeadZone();
        if (ComUtil.isEmpty(adjustDeadZone)) {
            log.error("f3: adjustDeadZone is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(16);
        // 数据单元标识：FN
        byteBuf.writeByte(0x03);
        // 数据包序号
        byteBuf.writeByte(sn);
        // 设定温度
        byteBuf.writeShortLE(BigDecimal.valueOf(temperatureSet).multiply(BigDecimal.valueOf(100)).shortValue());
        // 温度上限
        byteBuf.writeShortLE(BigDecimal.valueOf(temperatureUpper).multiply(BigDecimal.valueOf(100)).shortValue());
        // 温度下限
        byteBuf.writeShortLE(BigDecimal.valueOf(temperatureLower).multiply(BigDecimal.valueOf(100)).shortValue());
        // 调节死区
        byteBuf.writeShortLE(BigDecimal.valueOf(adjustDeadZone).multiply(BigDecimal.valueOf(100)).shortValue());
        // 预留:6个字节
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * f4: 解锁
     *
     * @param sn
     * @return
     */
    public static ByteBuf f4(int sn) {
        ByteBuf byteBuf = Unpooled.buffer(2);
        // 数据单元标识：FN
        byteBuf.writeByte(0x04);
        // 数据包序号
        byteBuf.writeByte(sn);
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * f5: 写累计工作时间
     *
     * @param sn
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf f5(int sn, CommandParamDTO commandParamDTO) {
        Integer workTimeTotal = commandParamDTO.getWorkTimeTotal();
        if (ComUtil.isEmpty(workTimeTotal)) {
            log.error("f5: workTimeTotal is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(6);
        // 数据单元标识：FN
        byteBuf.writeByte(0x05);
        // 数据包序号
        byteBuf.writeByte(sn);
        // 累计工作时间
        byteBuf.writeIntLE(workTimeTotal);
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * f6：写供暖期
     *
     * @param sn
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf f6(int sn, CommandParamDTO commandParamDTO) {
        String heatSeasonStart = commandParamDTO.getHeatSeasonStart();
        if (ComUtil.isEmpty(heatSeasonStart)) {
            log.error("f6: heatSeasonStart is empty");
            return null;
        }
        String heatSeasonEnd = commandParamDTO.getHeatSeasonEnd();
        if (ComUtil.isEmpty(heatSeasonEnd)) {
            log.error("f6: heatSeasonEnd is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(10);
        // 数据单元标识：FN
        byteBuf.writeByte(0x06);
        // 数据包序号
        byteBuf.writeByte(sn);
        // 供暖期开始时间:MMDD
        heatSeasonStart = heatSeasonStart.replace("-", "");
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray(heatSeasonStart));
        // 供暖期结束时间:MMDD
        heatSeasonEnd = heatSeasonEnd.replace("-", "");
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray(heatSeasonEnd));
        // 预留4字节
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * f7：读供暖期
     *
     * @param sn
     * @return
     */
    public static ByteBuf f7(int sn) {
        ByteBuf byteBuf = Unpooled.buffer(2);
        // 数据单元标识：FN
        byteBuf.writeByte(0x07);
        // 数据包序号
        byteBuf.writeByte(sn);
        return Unpooled.wrappedBuffer(packDefault(), byteBuf);
    }

    /**
     * fA017 透传报文: 写阀门控制
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param operateCode
     * @return
     */
    public static ByteBuf fA017(int sn, String deviceType, String macAddr, String operateCode) {
        if (ComUtil.isEmpty(operateCode)) {
            log.error("fA017: operateCode is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA017 = packA017(deviceType, macAddr, operateCode);
        // 长度
        byteBuf.writeByte(byteBufA017.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA017);
    }


    /**
     * fAc03 写是否启用温差、回温调节
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fAc03(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Integer autoAdjust = commandParamDTO.getAutoAdjust();
        if (ComUtil.isEmpty(autoAdjust)) {
            log.error("fAc03: autoAdjust is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc03 = packAc03(deviceType, macAddr, autoAdjust);
        // 长度
        byteBuf.writeByte(byteBufAc03.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc03);
    }

    /**
     * fAc04 写目标调节值
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fAc04(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Integer adjustMode = commandParamDTO.getAdjustMode();
        if (ComUtil.isEmpty(adjustMode)) {
            log.error("fAc04: adjustMode is empty");
            return null;
        }
        Double adjustValue = commandParamDTO.getAdjustValue();
        if (ComUtil.isEmpty(adjustValue)) {
            log.error("fAc04: adjustValue is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc04 = packAc04(deviceType, macAddr, adjustMode, adjustValue);
        if (byteBufAc04 != null) {
            // 长度
            byteBuf.writeByte(byteBufAc04.readableBytes());
            return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc04);
        }
        return null;
    }

    /**
     * fA028 写阀门开度上下限
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fA028(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Integer openDegreeUpper = commandParamDTO.getOpenDegreeUpper();
        if (ComUtil.isEmpty(openDegreeUpper)) {
            log.error("fA028: openDegreeUpper is empty");
            return null;
        }
        Integer openDegreeLower = commandParamDTO.getOpenDegreeLower();
        if (ComUtil.isEmpty(openDegreeLower)) {
            log.error("fA028: openDegreeLower is empty");
            return null;
        }
        if (openDegreeUpper <= openDegreeLower) {
            log.error("fA028 openDegreeUpper[{}] <= openDegreeLower[{}]", openDegreeUpper, openDegreeLower);
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA028 = packA028(deviceType, macAddr, openDegreeUpper, openDegreeLower);
        // 长度
        byteBuf.writeByte(byteBufA028.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA028);
    }

    /**
     * fAc01 写阀门所有配置
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fAc01(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        String heatSeasonStart = commandParamDTO.getHeatSeasonStart();
        String heatSeasonEnd = commandParamDTO.getHeatSeasonEnd();
        Integer openDegreeUpper = commandParamDTO.getOpenDegreeUpper();
        Integer openDegreeLower = commandParamDTO.getOpenDegreeLower();
        Integer cleanCycle = commandParamDTO.getCleanCycle();
        Integer adjustMode = commandParamDTO.getAdjustMode();
        Integer autoAdjust = commandParamDTO.getAutoAdjust();
        Double adjustValue = commandParamDTO.getAdjustValue();
        Integer adjustCycle = commandParamDTO.getAdjustCycle();
        Double adjustDeadZone = commandParamDTO.getAdjustDeadZone();
        Double coefficientP = commandParamDTO.getCoefficientP();
        Double coefficientI = commandParamDTO.getCoefficientI();
        Double coefficientD = commandParamDTO.getCoefficientD();
        Integer adjustRatio = commandParamDTO.getAdjustRatio();
        if (ComUtil.isEmpty(heatSeasonStart) || ComUtil.isEmpty(heatSeasonEnd) || ComUtil.isEmpty(openDegreeUpper) || ComUtil.isEmpty(openDegreeLower) || ComUtil.isEmpty(cleanCycle)
                || ComUtil.isEmpty(adjustMode) || ComUtil.isEmpty(autoAdjust) || (Constant.VALVE_ADJUST_MODE_0 != adjustMode && ComUtil.isEmpty(adjustValue)) || ComUtil.isEmpty(adjustCycle)
                || ComUtil.isEmpty(adjustDeadZone) || ComUtil.isEmpty(coefficientP) || ComUtil.isEmpty(coefficientI) || ComUtil.isEmpty(coefficientD) || ComUtil.isEmpty(adjustRatio)) {
            log.error("fAc01 参数不合法:{}", JsonUtil.safeJsonStr(commandParamDTO));
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc01 = packAc01(deviceType, macAddr, heatSeasonStart, heatSeasonEnd, openDegreeUpper, openDegreeLower, cleanCycle,
                adjustMode, autoAdjust, adjustValue, adjustCycle, adjustDeadZone, coefficientP, coefficientI, coefficientD, adjustRatio);
        // 长度
        byteBuf.writeByte(byteBufAc01.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc01);
    }

    /**
     * fac01 设置温度偏差
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fAc014EN14349988(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Double temperatureDiff = commandParamDTO.getTemperatureDiff();
        if (ComUtil.isEmpty(temperatureDiff)) {
            log.error("fAc014EN14349988 参数不合法:{}", JsonUtil.safeJsonStr(commandParamDTO));
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc01 = packAc014EN14349988(deviceType, macAddr, temperatureDiff);
        // 长度
        byteBuf.writeByte(byteBufAc01.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc01);
    }

    /**
     * fAb01 读调节阀所有配置参数
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fAb01(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAb01 = packAb01(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufAb01.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAb01);
    }

    /**
     * fab01 读温度偏差
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fAb014EN14349988(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAb01 = packAb014EN14349988(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufAb01.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAb01);
    }

    /**
     * fA02c 写清洗阀门周期
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fA02c(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Integer cleanCycle = commandParamDTO.getCleanCycle();
        if (ComUtil.isEmpty(cleanCycle)) {
            log.error("fA02c: cleanCycle is empty");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA02c = packA02c(deviceType, macAddr, cleanCycle);
        // 长度
        byteBuf.writeByte(byteBufA02c.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA02c);
    }

    /**
     * fA02d 读清洗阀门周期
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fA02d(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA02d = packA02d(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufA02d.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA02d);
    }

    /**
     * fAc05 写充值信息
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fAc05(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        Integer controlMode = commandParamDTO.getControlMode();
        String controlDateStart = commandParamDTO.getControlDateStart();
        String controlDateEnd = commandParamDTO.getControlDateEnd();
        Integer controlAvailableTime = commandParamDTO.getControlAvailableTime();
        if (ComUtil.isEmpty(controlMode)) {
            log.error("fAc05: controlMode is empty");
            return null;
        }
        if (controlMode == 0 && (ComUtil.isEmpty(controlDateStart) || ComUtil.isEmpty(controlDateEnd))) {
            log.error("fAc05: 时间段模式，充值时间段起止日期不能为空");
            return null;
        }
        if (controlMode == 1 && ComUtil.isEmpty(controlAvailableTime)) {
            log.error("fAc05: 小时模式，充值小时不能为空");
            return null;
        }

        String controlSerialNo = ComUtil.fillZeroLeft(RedisHelper.nextSN("control_" + macAddr, Constant.SN_MAX_CONTROL), 8);

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc05 = packAc05(deviceType, macAddr, controlMode, controlSerialNo, controlDateStart, controlDateEnd, controlAvailableTime);
        // 长度
        byteBuf.writeByte(byteBufAc05.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc05);
    }

    /**
     * fAb05 读充值信息
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fAb05(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAb05 = packAb05(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufAb05.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAb05);
    }

    /**
     * fAc07 充值信息清除
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fAc07(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufAc07 = packAc07(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufAc07.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufAc07);
    }

    /**
     * fA101 写充值水量信息
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fA101(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        String rechargeSerialNumber = commandParamDTO.getRechargeSerialNumber();
        Float rechargeVolume = commandParamDTO.getRechargeVolume();
        if (ComUtil.isEmpty(rechargeSerialNumber) || ComUtil.isEmpty(rechargeVolume)) {
            log.error("fA101: 充值序列号、充值量不能为空");
            return null;
        }
        if (rechargeSerialNumber.length() > 20) {
            log.error("fA101: 充值序列号长度不能超过20位");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA101 = packA101(deviceType, macAddr, rechargeSerialNumber, rechargeVolume);
        // 长度
        byteBuf.writeByte(byteBufA101.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA101);
    }

    /**
     * fA201 查询水量充值记录
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf fA201(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA201 = packA201(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBufA201.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA201);
    }

    /**
     * fA102 撤销某次水量充值
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @param commandParamDTO
     * @return
     */
    public static ByteBuf fA102(int sn, String deviceType, String macAddr, CommandParamDTO commandParamDTO) {
        String rechargeSerialNumber = commandParamDTO.getRechargeSerialNumber();
        if (ComUtil.isEmpty(rechargeSerialNumber)) {
            log.error("fA102: 充值序列号不能为空");
            return null;
        }
        if (rechargeSerialNumber.length() > 20) {
            log.error("fA102: 充值序列号长度不能超过20位");
            return null;
        }

        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBufA102 = packA102(deviceType, macAddr, rechargeSerialNumber);
        // 长度
        byteBuf.writeByte(byteBufA102.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBufA102);
    }

    /**
     * f1020 管理卡
     *
     * @param sn
     * @param deviceType
     * @param macAddr
     * @return
     */
    public static ByteBuf f1020(int sn, String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(3);
        // 数据单元标识：FN
        byteBuf.writeByte(0x01);
        // 数据包序号
        byteBuf.writeByte(sn);
        ByteBuf byteBuf1020 = pack1020(deviceType, macAddr);
        // 长度
        byteBuf.writeByte(byteBuf1020.readableBytes());
        return Unpooled.wrappedBuffer(packDefault(), byteBuf, byteBuf1020);
    }

    private static ByteBuf pack901f(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01（控制码）03（长度）901F（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103901F01"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA017(String deviceType, String macAddr, String operateCode) {
        ByteBuf byteBuf = Unpooled.buffer(17);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（写数据） 04(长度) A017 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0404A01701"));
        // operateCode: 55-强制开阀门; 66-普通开阀门; 77-普通关阀门; 88-阀门清洗; 99-强制关阀门; ff-自由控制
        byteBuf.writeByte(CodeUtil.hexStringToByte(operateCode, 0));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc03(String deviceType, String macAddr, Integer autoAdjust) {
        ByteBuf byteBuf = Unpooled.buffer(17);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（写数据） 04(长度) AC03 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0404AC0301"));
        // 是否启用温差、回温调节，00：启用；01：不启用
        byteBuf.writeByte(CodeUtil.hexStringToByte(ComUtil.fillZeroLeft(autoAdjust, 2), 0));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc04(String deviceType, String macAddr, Integer adjustMode, Double adjustValue) {
        ByteBuf byteBuf = Unpooled.buffer(19);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（写数据） 04(长度) AC04 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0406AC0401"));
        // 调节模式，00：通过面板在上下限之间控制,01：远程控制开度,02：回水温度控制开度，03：进回水温差控制开度
        byteBuf.writeByte(CodeUtil.hexStringToByte(ComUtil.fillZeroLeft(adjustMode, 2), 0));
        // 目标调节值（BCD码） 50%开度。调节模式不同含义不同，00：此处无用；01：表目标开度50%；02：表目标温度0.50摄氏度；03：表目标温差0.50摄氏度
        switch (adjustMode) {
            case 0:
                byteBuf.writeShortLE(0x0000);
                break;
            case 1:
                String percentageStr = ComUtil.fillZeroLeft(adjustValue.intValue(), 4);
                byteBuf.writeByte(CodeUtil.hexStringToByte(percentageStr.substring(2, 4), 0));
                byteBuf.writeByte(CodeUtil.hexStringToByte(percentageStr.substring(0, 2), 0));
                break;
            case 2:
            case 3:
                String temperatureStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(adjustValue).multiply(BigDecimal.valueOf(100)).intValue(), 4);
                byteBuf.writeByte(CodeUtil.hexStringToByte(temperatureStr.substring(2, 4), 0));
                byteBuf.writeByte(CodeUtil.hexStringToByte(temperatureStr.substring(0, 2), 0));
                break;
            default:
                log.error("packAc04: adjustMode[{}] match fail", adjustMode);
                return null;
        }
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA028(String deviceType, String macAddr, Integer openDegreeUpper, Integer openDegreeLower) {
        ByteBuf byteBuf = Unpooled.buffer(20);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04(控制码) 07(长度) A028(数据标识) 01(序号SER)
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0407A02801"));
        // 阀门开度上限
        String openDegreeUpperStr = ComUtil.fillZeroLeft(openDegreeUpper, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeUpperStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeUpperStr.substring(0, 2), 0));
        // 阀门开度下限
        String openDegreeLowerStr = ComUtil.fillZeroLeft(openDegreeLower, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeLowerStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeLowerStr.substring(0, 2), 0));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc01(String deviceType, String macAddr, String heatSeasonStart, String heatSeasonEnd, Integer openDegreeUpper, Integer openDegreeLower,
                                    Integer cleanCycle, Integer adjustMode, Integer autoAdjust, Double adjustValue, Integer adjustCycle, Double adjustDeadZone,
                                    Double coefficientP, Double coefficientI, Double coefficientD, Integer adjustRatio) {
        ByteBuf byteBuf = Unpooled.buffer(42);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04(控制码) 1D(长度) AC01(数据标识) 01(序号SER)
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("041DAC0101"));
        // 采暖季开始
        heatSeasonStart = heatSeasonStart.replace("-", "");
        byteBuf.writeByte(CodeUtil.hexStringToByte(heatSeasonStart.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(heatSeasonStart.substring(0, 2), 0));
        // 采暖季结束
        heatSeasonEnd = heatSeasonEnd.replace("-", "");
        byteBuf.writeByte(CodeUtil.hexStringToByte(heatSeasonEnd.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(heatSeasonEnd.substring(0, 2), 0));
        // 开度上限
        String openDegreeUpperStr = ComUtil.fillZeroLeft(openDegreeUpper, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeUpperStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeUpperStr.substring(0, 2), 0));
        // 开度下限
        String openDegreeLowerStr = ComUtil.fillZeroLeft(openDegreeLower, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeLowerStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(openDegreeLowerStr.substring(0, 2), 0));
        // 清洗周期
        String cleanCycleStr = ComUtil.fillZeroLeft(cleanCycle, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(cleanCycleStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(cleanCycleStr.substring(0, 2), 0));
        // 调节模式：0-面板控制；1-远程控制开度；2-回水温度控制开度；3-进回水温差控制开度
        byteBuf.writeByte(adjustMode);
        // 是否启用自动调平：0-启用；1-不启用
        byteBuf.writeByte(autoAdjust);
        // 目标调节值（BCD码）50%开度，调节模式不同含义不同，调节模式为00：此处无用；01：表目标开度；02：表目标温度；03：表目标温差
        switch (adjustMode) {
            case 0:
                byteBuf.writeShortLE(0x0000);
                break;
            case 1:
                String percentageStr = ComUtil.fillZeroLeft(adjustValue.intValue(), 4);
                byteBuf.writeByte(CodeUtil.hexStringToByte(percentageStr.substring(2, 4), 0));
                byteBuf.writeByte(CodeUtil.hexStringToByte(percentageStr.substring(0, 2), 0));
                break;
            case 2:
            case 3:
                String temperatureStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(adjustValue).multiply(BigDecimal.valueOf(100)).intValue(), 4);
                byteBuf.writeByte(CodeUtil.hexStringToByte(temperatureStr.substring(2, 4), 0));
                byteBuf.writeByte(CodeUtil.hexStringToByte(temperatureStr.substring(0, 2), 0));
                break;
            default:
                log.error("packAc01: adjustMode[{}] match fail", adjustMode);
                return null;
        }
        // 调节周期
        String adjustCycleStr = ComUtil.fillZeroLeft(adjustCycle, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustCycleStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustCycleStr.substring(0, 2), 0));
        // 调节死区
        String adjustDeadZoneStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(adjustDeadZone).multiply(BigDecimal.valueOf(100)).intValue(), 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustDeadZoneStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustDeadZoneStr.substring(0, 2), 0));
        // P
        String pStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(coefficientP).multiply(BigDecimal.valueOf(100)).intValue(), 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(pStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(pStr.substring(0, 2), 0));
        // I
        String iStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(coefficientI).multiply(BigDecimal.valueOf(100)).intValue(), 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(iStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(iStr.substring(0, 2), 0));
        // D
        String dStr = ComUtil.fillZeroLeft(BigDecimal.valueOf(coefficientD).multiply(BigDecimal.valueOf(100)).intValue(), 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(dStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(dStr.substring(0, 2), 0));
        // 调节比例
        String adjustRatioStr = ComUtil.fillZeroLeft(adjustRatio, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustRatioStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(adjustRatioStr.substring(0, 2), 0));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc014EN14349988(String deviceType, String macAddr, Double temperatureDiff) {
        ByteBuf byteBuf = Unpooled.buffer(18);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04(控制码) 05(长度) AC01(数据标识) 01(序号SER)
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0405AC0101"));
        // 温度偏差
        byteBuf.writeShortLE(BigDecimal.valueOf(temperatureDiff).multiply(BigDecimal.valueOf(100)).shortValue());
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAb01(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01(控制码) 03(长度) AB01(数据标识) 01(序号SER)
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103AB0101"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAb014EN14349988(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01(控制码) 03(长度) AB01(数据标识) 01(序号SER)
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103AB0101"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA02c(String deviceType, String macAddr, Integer cleanCycle) {
        ByteBuf byteBuf = Unpooled.buffer(18);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（控制码）05（长度）A02C（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0405A02C01"));
        // 清洗周期
        String cleanCycleStr = ComUtil.fillZeroLeft(cleanCycle, 4);
        byteBuf.writeByte(CodeUtil.hexStringToByte(cleanCycleStr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(cleanCycleStr.substring(0, 2), 0));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA02d(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01（控制码）03（长度）A02D（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103A02D01"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc05(String deviceType, String macAddr, Integer controlMode, String controlSerialNo, String controlDateStart, String controlDateEnd, Integer controlAvailableTime) {
        ByteBuf byteBuf = Unpooled.buffer(31);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（控制码）12（长度）AC05（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0412AC0501"));
        // 控制模式：00：充值时间段启作用；01充值小时启作用
        byteBuf.writeByte(CodeUtil.hexStringToByte(ComUtil.fillZeroLeft(controlMode, 2), 0));
        // 充值流水号：4字节
        byteBuf.writeByte(CodeUtil.hexStringToByte(controlSerialNo.substring(6, 8), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(controlSerialNo.substring(4, 6), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(controlSerialNo.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(controlSerialNo.substring(0, 2), 0));
        // 充值时间段：6字节
        if (controlMode == 0) {
            // 开始
            controlDateStart = controlDateStart.replace("-", "").substring(2);
            String controlDateStartStr = ComUtil.fillZeroLeft(controlDateStart, 6);
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateStartStr.substring(4, 6), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateStartStr.substring(2, 4), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateStartStr.substring(0, 2), 0));
            // 结束
            controlDateEnd = controlDateEnd.replace("-", "").substring(2);
            String controlDateEndStr = ComUtil.fillZeroLeft(controlDateEnd, 6);
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateEndStr.substring(4, 6), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateEndStr.substring(2, 4), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlDateEndStr.substring(0, 2), 0));
        } else {
            byteBuf.writeMedium(0x000000);
            byteBuf.writeMedium(0x000000);
        }
        // 充值小时：4字节
        if (controlMode == 1) {
            String controlAvailableTimeStr = ComUtil.fillZeroLeft(controlAvailableTime, 8);
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlAvailableTimeStr.substring(6, 8), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlAvailableTimeStr.substring(4, 6), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlAvailableTimeStr.substring(2, 4), 0));
            byteBuf.writeByte(CodeUtil.hexStringToByte(controlAvailableTimeStr.substring(0, 2), 0));
        } else {
            byteBuf.writeInt(0x00000000);
        }
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAb05(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01（控制码）03（长度）AB05（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103AB0501"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packAc07(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（控制码）03（长度）AC07（数据标识）01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0403AC0701"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA101(String deviceType, String macAddr, String rechargeSerialNumber, Float rechargeVolume) {
        ByteBuf byteBuf = Unpooled.buffer(40);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（写数据） 1B(长度) A101 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("041BA10101"));
        // rechargeSerialNumber: 充值序列号。类型ASCII。20字节
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray(CodeUtil.asciiStringToHexString(rechargeSerialNumber)));
        for (int i = 0, len = 20 - rechargeSerialNumber.length(); i < len; i++) {
            byteBuf.writeByte(0x00);
        }
        // rechargeVolume: 本次充值水量，单位m³，类型float
        byteBuf.writeFloatLE(rechargeVolume);
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA201(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(16);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 01（写数据） 03(长度) A201 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0103A20101"));
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf packA102(String deviceType, String macAddr, String rechargeSerialNumber) {
        ByteBuf byteBuf = Unpooled.buffer(36);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 04（写数据） 17(长度) A102 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("0417A10201"));
        // rechargeSerialNumber: 充值序列号。类型ASCII。20字节
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray(CodeUtil.asciiStringToHexString(rechargeSerialNumber)));
        for (int i = 0, len = 20 - rechargeSerialNumber.length(); i < len; i++) {
            byteBuf.writeByte(0x00);
        }
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    private static ByteBuf pack1020(String deviceType, String macAddr) {
        ByteBuf byteBuf = Unpooled.buffer(45);
        // head
        packHead(byteBuf, deviceType, macAddr);
        // 固定hex：5字节: 24（控制码） 20(长度) 1020 01
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("2420102001"));
        // T5557卡第1块内容：卡型为管理卡功能-20
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00200000"));
        // T5557卡第2块内容：保留
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00000000"));
        // T5557卡第3块内容：保留
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00000000"));
        // T5557卡第4块内容：保留
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00000000"));
        // T5557卡第5块内容：保留
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00000000"));
        // T5557卡第6块内容：模式标志为热表-AA，校验码-8A
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("00008AAA"));
        // T5557卡第7块内容：管理卡密码
        byteBuf.writeBytes(CodeUtil.hexStringToByteArray("13202807"));
        // 保留
        byteBuf.writeByte(0x00);
        // tail
        packTail(byteBuf);
        return byteBuf;
    }

    /**
     * 命令包：默认
     *
     * @return
     */
    private static ByteBuf packDefault() {
        ByteBuf byteBuf = Unpooled.buffer(2);
        // 功能码：AFN
        byteBuf.writeByte(0x0c);
        // 帧序列：SEQ，默认FF
        byteBuf.writeByte(0xFF);
        return byteBuf;
    }

    /**
     * 组包 头部
     *
     * @param byteBuf
     * @param deviceType
     * @param macAddr
     */
    private static void packHead(ByteBuf byteBuf, String deviceType, String macAddr) {
        byteBuf.writeByte(0x68);
        // 仪表类型：1字节
        byteBuf.writeByte(CodeUtil.hexStringToByte(deviceType, 0));
        // macAddr：7字节
        byteBuf.writeByte(CodeUtil.hexStringToByte(macAddr.substring(6, 8), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(macAddr.substring(4, 6), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(macAddr.substring(2, 4), 0));
        byteBuf.writeByte(CodeUtil.hexStringToByte(macAddr.substring(0, 2), 0));
        byteBuf.writeByte(0x00);
        byteBuf.writeByte(0x00);
        byteBuf.writeByte(0x00);
    }

    /**
     * 组包 尾部
     *
     * @param byteBuf
     */
    private static void packTail(ByteBuf byteBuf) {
        // checksum
        int checksum = 0;
        for (int i = 0, len = byteBuf.readableBytes(); i < len; i++) {
            checksum += byteBuf.getByte(i);
        }
        byteBuf.writeByte(checksum % 256);
        // 16
        byteBuf.writeByte(0x16);
    }
}
